﻿using System;

namespace StockLib.Indicator
{
    /***
    指数指数平均值
    EMA(n)= n 日平滑系数 × （今日收盘价－昨日 EMA ） + 昨日 EMA 
    n 日平滑系数 =2÷ （ n+1 ） 
	
    EMA  = 短期指数移动均值
	EMA2 = 长期指数移动均值
	DIF  = 短期移动均值 - 长期移动均值
	DEA  = DIF的移动平滑值
	柱状线值 = DIF - DEA
    */
    public partial class StockMacdIndicator : StockIndicator
    {
        private int ema1Days;
        private int ema2Days;
        private int difDays;

        public StockMacdIndicator()
            : base()
        {
            cacheCount = 3;
        }

        public override void SetDefaultParameters()
        {
            ema1Days = 12;
            ema2Days = 26;
            difDays = 9;
        }

        protected override float[] CalcOutput(int index)
        {
            float[] outputValues = new float[3];
            outputValues[0] = CalcCloseEmaCache(index, ema1Days, 0) - CalcCloseEmaCache(index, ema2Days, 1);
            outputValues[1] = CalcDeaEmaCache(index, difDays);
            outputValues[2] = (outputValues[0] - outputValues[1]) * 2;
            return outputValues;
        }

        private float CalcDeaEmaCache(int index, int days)
        {
            if (!cacheValues[2].ContainsKey(index))
            {
                float val = CalcCloseEmaCache(index, ema1Days, 0) - CalcCloseEmaCache(index, ema2Days, 1);
                float ema;
                if (index <= 0)
                {
                    ema = val;
                }
                else
                {
                    float emaLast = CalcDeaEmaCache(index - 1, days);
                    ema = (2.0f / (days + 1)) * (val - emaLast) + emaLast;
                }
                cacheValues[2].Add(index, ema);
            }

            return cacheValues[2][index];
        }

        private float CalcCloseEmaCache(int index, int days, int cacheIndex)
        {
            if (cacheIndex < 0 || cacheIndex >= cacheCount)
                throw new IndexOutOfRangeException("缓冲索引超出范围");
            
            if (!cacheValues[cacheIndex].ContainsKey(index))
            {
                float val = kData[index].Close;
                float ema;
                if (index <= 0)
                {
                    ema = val;
                }
                else
                {
                    float emaLast = CalcCloseEmaCache(index - 1, days, cacheIndex);
                    ema = (2.0f / (days + 1)) * (val - emaLast) + emaLast;
                }

                cacheValues[cacheIndex].Add(index, ema);
            }

            return cacheValues[cacheIndex][index];
        }
    }
}
